<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Signals &amp; events in PyGTK</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, PyGTK, events, Python, programming, Linux">
<meta nam="description" content="Events in PyGTK">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div> 

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Signals &amp; events in PyGTK</h1>

<p>
In this part of the PyGTK programming tutorial, we will talk about signals &amp; events.
</p>

<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* NewSquare */
google_ad_slot = "0364418177";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script>

<p>
All GUI applications are event driven. PyGTK applications are no exception.
The applications start a main loop with the <b class="keyword">gtk.main()</b> call, 
which continuously checks for newly generated events. 
If there is no event, the application waits and does nothing. 
</p>

<p>
<b class="keyword">Events</b> are messages from the X server to the application.
When we click on a button widget, the clicked signal will be <b class="keyword">emitted</b>.
There are signals that all widgets inherit, such as destroy, and there are signals that are 
widget specific, such as toggled on a toggle button.
</p>

<p>
Programmers use signal handlers to react to various signals. These handlers are
called <b class="keyword">callbacks</b> among GTK programmers. 
</p>

<pre>
handler_id = button.connect("clicked", self.on_clicked)
</pre>

<p>
Here we use the <b class="keyword">connect()</b> method of the GObject class, (GtkButton is a GObject), 
to connect a callback <b class="keyword">on_clicked()</b> to a signal called <b class="keyword">clicked</b>.
</p>
<p>
The connect() method returns a handler id, which is used to uniquely identify
the callback method. The id can be used with the following methods:
</p>

<pre>
 def disconnect(handler_id)
 def handler_disconnect(handler_id)
 def handler_is_connected(handler_id)
 def handler_block(handler_id)
 def handler_unblock(handler_id)
</pre>

<p>
These methods enable to disconnect a handler from an GObject, or block/unblock it.
</p>


<h2>Signals vs events</h2>

<p>
There is generally a lot of confusion about the difference 
between the two. 
</p>

<p>
Signals and events are two different things.
An event is an almost one-to-one mapping of window system events. 
Key press, window resizement or button press are typical window
system events. Window system events are reported to the application main loop.
Gdk interprets the window system events and passes them along via signals.
</p>

<p>
A signal is nothing other than a callback mechanism.
If one object wants to be notified about an other object's action or
state change, it registers a callback. When the object emits a signal,
it looks in the list of callbacks which have been registered with it
and calls the callback(s) for the specific signal. It can optionally
send some predefined data with it.
</p>

<p>
Signals are a general purpose notification framework.
They are not used only for notifications about UI changes.
They can be used for notifications about application state
changes. Signals are general, powerful, their usage is very broad.
Any GObject can emit and receive a signal. 
A type may have one or more signals, each of which may 
have an argument list and return value. Handlers can then be connected
to instances of the type. When the signal is emitted on an instance,
each of the connected handlers will be called.
</p>

<p>
The only connection between signals and events is that signals are used 
to send notifications about events from the X server.
</p>

<p>
Signals are a feature of gtk.Object and its subclasses, 
events are a Gdk/Xlib concept.
</p>



<h2>Simple example</h2>

<p>
The next example shows, how we react to two basic signals.
</p>

<div class="codehead">quitbutton.py</div>
<pre class="code"> 
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# The example shows how to work with 
# destroy and clicked signals
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window):
    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Quit Button")
        self.set_size_request(250, 200)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", self.on_destroy)
        
        fixed = gtk.Fixed()

        quit = gtk.Button("Quit")
        quit.connect("clicked", self.on_clicked)
        quit.set_size_request(80, 35)

        fixed.put(quit, 50, 50)

        self.add(fixed)
        self.show_all()
        
    def on_destroy(self, widget):
        gtk.main_quit()
        
    def on_clicked(self, widget):
        gtk.main_quit()


PyApp()
gtk.main()
</pre>

<p>
The destroy signal is triggered, when we close the window.  By default, the
application does not quit, when we click on the close button in the titlebar. 
</p>


<pre class="explanation">
 self.connect("destroy", self.on_destroy)
</pre>

<p>
The <b class="keyword">connect()</b> method plugs 
the <b class="keyword">on_destroy()</b> method 
to the <b class="keyword">destroy</b> signal. 
</p>

<pre class="explanation">
 quit.connect("clicked", self.on_clicked)
</pre>

<p>
Pressing the quit button, the <b class="keyword">clicked</b>
signal is triggered.
When we click on the quit button, we call the
<b class="keyword">on_clicked()</b> method.
</p>

<pre class="explanation">
 def on_destroy(self, widget):
     gtk.main_quit()
</pre>

<p>
In the <b class="keyword">on_destroy()</b> method, we react 
to the <b class="keyword">destroy</b> signal. 
We call the <b class="keyword">gtk.main_quit()</b> method, which
terminates the application.
</p>

<pre class="explanation">
 def on_clicked(self, widget):
     gtk.main_quit()
</pre>

<p>
Here is the <b class="keyword">on_clicked()</b> method. It takes two parameters. 
The widget parameter is the object, which triggered this signal. In our case it 
is the quit button. Different objects send different signals. 
Signals and the parameters sent to methods can be found in the reference manual of
the PyGTK library.
<a href="http://pygtk.org/docs/pygtk/index.html">pygtk.org/docs/pygtk/index.html</a>
</p>


<h2>Creating a custom signal</h2>

<p>
In the following code example, we create and send a custom singal. 
</p>

<div class="codehead">customsignal.py</div>
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows how to create
# and send a custom singal
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gobject


class Sender(gobject.GObject):
    def __init__(self):
        self.__gobject_init__()
        

gobject.type_register(Sender)
gobject.signal_new("z_signal", Sender, gobject.SIGNAL_RUN_FIRST,
                   gobject.TYPE_NONE, ())


class Receiver(gobject.GObject):
    def __init__(self, sender):
        self.__gobject_init__()
        
        sender.connect('z_signal', self.report_signal)
        
    def report_signal(self, sender):
        print "Receiver reacts to z_signal"


def user_callback(object):
    print "user callback reacts to z_signal"

if __name__ == '__main__':
    
    sender = Sender()
    receiver = Receiver(sender)

    sender.connect("z_signal", user_callback)
    sender.emit("z_signal")
</pre>


<p>
We create two <b class="keyword">GObjects</b>. Sender and receiver objects. 
The sender emits a signal, which is received by the
receiver object. We also plug a callback to the 
signal.
</p>


<pre class="explanation">
 class Sender(gobject.GObject):
     def __init__(self):
         self.__gobject_init__()
</pre>

<p>
This is a sender object. It is created with a default constructor.
</p>

<pre class="explanation">
 gobject.type_register(Sender)
 gobject.signal_new("z_signal", Sender, gobject.SIGNAL_RUN_FIRST,
                   gobject.TYPE_NONE, ())
</pre>

<p>
We register a new object and a new signal. 
The <b class="keyword">signal_new()</b> function registers a signal 
called <b class="keyword">z_signal</b> for the Sender object. 
The <b class="keyword">SIGNAL_RUN_FIRST</b> parameter means
that the default handler of the object that receives the signal is
called as first. The last two parameters are the return value type
and parameter types. In our example we do not return any value and
send no parameters.
</p>

<pre class="explanation">
 sender.connect('z_signal', self.report_signal)
</pre>

<p>
The receiver listens for the <b class="keyword">z_signal</b>.
</p>

<pre class="explanation">
 sender = Sender()
 receiver = Receiver(sender)
</pre>

<p>
Sender and receiver objects are instantiated. The receiver takes
a sender as a parameter, so that it can listen to its signals.
</p>

<pre class="explanation">
 sender.connect("z_signal", user_callback)
</pre>

<p>
Here we plug the signal to the user callback.
</p>

<pre class="explanation">
 sender.emit("z_signal")
</pre>

<p>
The <b class="keyword">z_signal</b> is being emitted.
</p>


<pre class="code">

class Sender(gobject.GObject):

    __gsignals__ = {
        'z_signal': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
    }

    def __init__(self):
        self.__gobject_init__() 
        
gobject.type_register(Sender)
</pre>

<p>
We can also use the <b class="keyword">__gsignals__</b>
class attribute to register a new singal. 
</p>


<h2>Predefined signal handlers</h2>

<p>
Objects in PyGTK may have predefined signal handlers. These handlers
begin with do_*. For example do_expose(), do_show() or do_clicked().
</p>

<div class="codehead">move.py</div>
<pre class="code"> 
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example overrides predefined
# do_configure_event() signal handler
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk
import gobject

class PyApp(gtk.Window):
    __gsignals__ = {
        "configure-event" : "override"
        }

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(200, 150)
        self.set_position(gtk.WIN_POS_CENTER)
       
        self.connect("destroy", gtk.main_quit)

        self.show_all()

    def do_configure_event(self, event):
        
        title = "%s, %s" % (event.x, event.y)
        self.set_title(title)
        gtk.Window.do_configure_event(self, event)
       

PyApp()
gtk.main()
</pre>

<p>
When we move or resize a window, the X server sends configure events. 
These are then transformed into <b class="keyword">configure-event</b> signals. 
</p>

<p>
In our code example, we display the x, y coordinates of the top-left corner
of the window in the titlebar. We could simply connect a signal handler to the
<b class="keyword">configure-event</b> signal. But we take a different strategy.
We override the default class handler, where we implement the logic needed.
</p>

<pre class="explanation">
 __gsignals__ = {
     "configure-event" : "override"
     }
</pre>

<p>
This tells, that we are going to override the default <b class="keyword">on_configure_event()</b>
method.
</p>

<pre class="explanation">
 def do_configure_event(self, event):
        
     title = "%s, %s" % (event.x, event.y)
     self.set_title(title)
     gtk.Window.do_configure_event(self, event)
</pre>


<p>
Here we override the predefined <b class="keyword">do_configure_event()</b> method. 
We set the x, y coordinates of the window to the title of the window. 
Also note the last line. It explicitly calls the superclass <b class="keyword">do_configure_event()</b> method.
This is beacuse it does some important job. Try to comment this line to see what happens. Resizing
of windows would not work correctly. If we override a default handler, we may or may not call
the superclass method. In our case we have to. 
</p>


<br>
<img src="/img/gui/pygtk/move.png" alt="Configure signal">
<div class="figure">Figure: Configure singal</div>
<br>



<h2>Signals of a button</h2>

<p>
The following example shows various button signals.
</p>

<div class="codehead">buttonsignals.py</div>
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program shows various signals 
# of a button widget
# It emits a button-release-event which
# triggers a released singal
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk


class PyApp(gtk.Window):
    def __init__(self):
        super(PyApp, self).__init__()
        
        self.set_title("Signals")
        self.set_size_request(250, 200)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)
        
        fixed = gtk.Fixed()
        
        self.quit = gtk.Button("Quit")
        
        self.quit.connect("pressed", self.on_pressed)
        self.quit.connect("released", self.on_released)
        self.quit.connect("clicked", self.on_clicked)
        
        self.quit.set_size_request(80, 35)

        fixed.put(self.quit, 50, 50)
        
        self.add(fixed)
        self.show_all()
        self.emit_signal()
        
    def emit_signal(self):
                
        event = gtk.gdk.Event(gtk.gdk.BUTTON_RELEASE)
        event.button = 1
        event.window = self.quit.window
        event.send_event = True
                
        self.quit.emit("button-release-event", event)
        
        
    def on_clicked(self, widget):
        print "clicked"
        
    def on_released(self, widget):
        print "released"
        
    def on_pressed(self, widget):
        print "pressed"


PyApp()
gtk.main()
</pre>

<p>
A button can emit more than just one type of signal. 
We work with three of them. The <b class="keyword">clicked</b>,
<b class="keyword">pressed</b> and <b class="keyword">released</b> signals. 
We also show, how an event signal triggers another signal.
</p>

<pre class="explanation">
 self.quit.connect("pressed", self.on_pressed)
 self.quit.connect("released", self.on_released)
 self.quit.connect("clicked", self.on_clicked)
</pre>

<p>
We register callbacks for all three signals.
</p>

<pre class="explanation">
 self.emit_signal()
</pre>

<p>
Upon the start of the application, we emit a specific signal.
</p>


<pre class="explanation">
 def emit_signal(self):
                
     event = gtk.gdk.Event(gtk.gdk.BUTTON_RELEASE)
     event.button = 1
     event.window = self.quit.window
     event.send_event = True
                
     self.quit.emit("button-release-event", event)
</pre>

<p>
We emit the <b class="keyword">button-release-event</b> signal. 
It takes an <b class="keyword">Event</b> object as a parameter.
After the application starts, we should see "released" text in 
our console window. When we click on the button, all three signals
are triggered. 
</p>



<h2>Blocking an event handler</h2>

<p>
We can block a signal handler. The next example shows this.
</p>

<div class="codehead">block.py</div>
<pre class="code">
#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows how to block/unblock
# a signal handler
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009


import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Blocking a callback")
        self.set_size_request(250, 180)
        self.set_position(gtk.WIN_POS_CENTER)
        
        fixed = gtk.Fixed()
        button = gtk.Button("Click")
        button.set_size_request(80, 35)
        self.id = button.connect("clicked", self.on_clicked)
        fixed.put(button, 30, 50)

        check = gtk.CheckButton("Connect")
        check.set_active(True)
        check.connect("clicked", self.toggle_blocking, button)
        fixed.put(check, 130, 50)


        self.connect("destroy", gtk.main_quit)

        self.add(fixed)
        self.show_all()

    def on_clicked(self, widget):
        print "clicked"

    def toggle_blocking(self, checkbox, button):
        if checkbox.get_active():
           button.handler_unblock(self.id)
        else:
           button.handler_block(self.id)

PyApp()
gtk.main()
</pre>

<p>
In the code example, we have a button and a check box. We show "clicked" text in the
console, when we click on the button and the check box is active. 
The check box blocks/unblocks a handler method from the button 
<b class="keyword">clicked</b> signal. 
</p>

<pre class="explanation">
 self.id = button.connect("clicked", self.on_clicked)
</pre>

<p>
The <b class="keyword">connect()</b> method returns a handler id. This
id is used to block and unblock the handler. 
</p>

<pre class="explanation">
 def toggle_blocking(self, checkbox, button):
     if checkbox.get_active():
        button.handler_unblock(self.id)
     else:
        button.handler_block(self.id)
</pre>

<p>
These lines block and unblock the callback with the appropriate
methods.
</p>

<br>
<img src="/img/gui/pygtk/blocking.png" alt="blocking a callback">
<div class="figure">Figure: Blocking a callback</div>


<hr class="btm">

<p>
In this chapter of the PyGTK tutorial, we worked with signals. 
</p>


<br>
<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>  
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified January 23, 2009  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

